package com.me.study.jdk8.date;

import org.junit.Before;
import org.junit.Test;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.UnsupportedTemporalTypeException;

import static org.junit.Assert.assertEquals;

/**
 * Java8：LocalDate 测试类
 *
 * @author ME
 * @date 2021/7/31
 */
public class LocalDateTest {

    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter YYYYMM_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM");
    LocalDate date;

    @Before
    public void before() {
        date = LocalDate.of(2020, 9, 12);
    }

    /**
     * 日期格式化、日期字符串解析
     */
    @Test
    public void format() {
        assertEquals("`2020-09-12` 格式化输出", "2020-09-12", FORMATTER.format(date));
        assertEquals("`2020-09-12` 格式化输出", "2020-09-12", DateTimeFormatter.ISO_DATE.format(date));
        assertEquals("`2020-09-12` 格式化输出", "2020-09-12", DateTimeFormatter.ISO_LOCAL_DATE.format(date));
    }

    /**
     * LocalDateTime 可以格式化为 `yyyy-MM-dd`字符串
     */
    @Test
    public void time2dateStr() {
        String dateTime = FORMATTER.format(LocalDateTime.of(2020, 1, 3, 19, 25, 30));
        assertEquals("2020-01-03", dateTime);
    }

    /**
     * `yyyy-MM-dd HH:mm:ss`字符串 可以可以可以可以可以解析成 LocalDate，并且 MySQL的 datetime 也可以映射成 LocalDate
     */
    @Test
    public void timeStr2date() {
        LocalDate localDate = LocalDate.parse("2019-12-03 08:15:00", LocalDateTimeTest.FORMATTER);
        assertEquals("2019-12-03", localDate.toString());
    }

    /**
     * UnsupportedTemporalTypeException    <br>
     *
     * TODO
     *  LocalDate 不能格式化为 `yyyy-MM-dd HH:mm:ss`
     */
    @Test
    public void date2timeStr() {
        // LocalDate 不能格式化为 `yyyy-MM-dd HH:mm:ss`
        LocalDateTimeTest.FORMATTER.format(date);
    }

    /**
     * TODO DateTimeParseException
     *  `yyyy-MM-dd`字符串 不能解析成 LocalDateTime
     */
    @Test
    public void dateStr2time() {
        // `yyyy-MM-dd` 不能解析成 LocalDateTime
        LocalDateTime.parse("2020-09-12", FORMATTER);
    }

    /**
     * 日期格式化、日期字符串解析
     */
    @Test
    public void yyyyMM() {
        System.out.println(YearMonth.of(2020, 1).minusMonths(2));
        assertEquals("`2020-09` 解析为 YearMonth", YearMonth.of(2020, 9), YearMonth.parse("2020-09"));
    }

    /**
     * 日期格式化、日期字符串解析
     */
    @Test
    public void parse() {
        assertEquals("`2020-09-12` 解析为 LocalDate", date, LocalDate.from(FORMATTER.parse("2020-09-12")));
        DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyyMMdd");
        assertEquals("`2020-09-12` 解析为 LocalDate", date, LocalDate.from(formatter1.parse("20200912")));

        assertEquals("`2020-09-12` 解析为 LocalDate", date, LocalDate.parse("2020-09-12+08:00", DateTimeFormatter.ISO_DATE));
    }

    /**
     * 获取一些特殊时间点：如年第一天、年最后一天、月初、月末
     */
    @Test
    public void temporalAdjusters() {
        assertEquals("`2020-09-12` 那年的第一天为：", "2020-01-01",
                FORMATTER.format(date.with(TemporalAdjusters.firstDayOfYear())));
        assertEquals("`2020-09-12` 下一年的第一天为：", "2021-01-01",
                FORMATTER.format(date.with(TemporalAdjusters.firstDayOfNextYear())));
        assertEquals("`2020-09-12` 那年的最后一天为：", "2020-12-31",
                FORMATTER.format(date.with(TemporalAdjusters.lastDayOfYear())));

        assertEquals("`2020-09-12` 所在月的第一天为：", "2020-09-01",
                FORMATTER.format(date.with(TemporalAdjusters.firstDayOfMonth())));
        assertEquals("`2020-09-12` 当月的第三天：", "2020-09-03",
                FORMATTER.format(date.withDayOfMonth(3)));
        assertEquals("`2020-09-12` 下个月的一天为：", "2020-10-01",
                FORMATTER.format(date.with(TemporalAdjusters.firstDayOfNextMonth())));
        assertEquals("`2020-09-12` 那个月的最后一天为：", "2020-09-30",
                FORMATTER.format(date.with(TemporalAdjusters.lastDayOfMonth())));

        // 月初是一年中的第几天（需要区分是否是闰年）
        assertEquals("`2020-09-12` 是一年中的第 245 天", 245, date.getMonth().firstDayOfYear(date.isLeapYear()));
    }

    /**
     * TODO 季度计算
     */
    @Test
    public void quarter() {
        Month month = date.getMonth();
        // 季度第一个月是 7月
        Month firstMonthOfQuarter = month.firstMonthOfQuarter();
        // 本季度第五天是
        LocalDate of = LocalDate.of(date.getYear(), firstMonthOfQuarter, 5);
        assertEquals("`2020-09-12` 本季度的第五天为：", "2020-07-05", FORMATTER.format(of));

        // 下个季度5号
        firstMonthOfQuarter = month.firstMonthOfQuarter().plus(3);
        of = LocalDate.of(date.getYear(), firstMonthOfQuarter, 5);
        assertEquals("`2020-09-12` 下个季度的第五天为：", "2020-10-05", FORMATTER.format(of));

        // 季度最后一个月是 9月
        Month endMonthOfQuarter = Month.of(firstMonthOfQuarter.getValue() + 2);
        // 本季度最后一个月的第一天是
        LocalDate of2 = LocalDate.of(date.getYear(), firstMonthOfQuarter.getValue() + 2, 1);
        assertEquals("`2020-09-12` 本季度最后一个月的第一天为：", "2020-12-01", FORMATTER.format(of2));
    }

}
